home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 June / ccd0605.iso / Software / Freeware / Programare / highlight / highlight-W32GUI-2.2-10b-Setup.exe / {app} / src / codegenerator.cpp < prev    next >
C/C++ Source or Header  |  2005-03-31  |  38KB  |  1,418 lines

  1. /***************************************************************************
  2.                           codeparser.cpp  -  description
  3.                              -------------------
  4.     begin                : Die Jul 9 2002
  5.     copyright            : (C) 2002 by AndrΘ Simon
  6.     email                : andre.simon1@gmx.de
  7.  ***************************************************************************/
  8.  
  9. /***************************************************************************
  10.  *                                                                         *
  11.  *   This program is free software; you can redistribute it and/or modify  *
  12.  *   it under the terms of the GNU General Public License as published by  *
  13.  *   the Free Software Foundation; either version 2 of the License, or     *
  14.  *   (at your option) any later version.                                   *
  15.  *                                                                         *
  16.  ***************************************************************************/
  17.  
  18. #include "codegenerator.h"
  19.  
  20. #include "htmlgenerator.h"
  21. #include "xhtmlgenerator.h"
  22. #include "rtfgenerator.h"
  23. #include "latexgenerator.h"
  24. #include "texgenerator.h"
  25. #include "xslfogenerator.h"
  26. #include "xmlgenerator.h"
  27. #ifndef __WXMSW__
  28.   #include "ansigenerator.h"
  29. #endif
  30.  
  31.  
  32. using namespace std;
  33.  
  34. namespace highlight {
  35.  
  36. CodeGenerator* CodeGenerator::generator=NULL;
  37.  
  38. CodeGenerator* CodeGenerator::getInstance(OutputType type,
  39.                                           const string& styleInfoPath,
  40.                                           const string& styleInPath,
  41.                                           const string& styleOutPath,
  42.                                           const string& encoding,
  43.                                           bool includeStyle,
  44.                                           bool attachAnchors,
  45.                                           bool replaceQuotes,
  46.                                           bool fopCompatible,
  47.                                           int numSpaces,
  48.                                           WrapMode lineWrappingMode,
  49.                                           bool ln,
  50.                                           bool lnz,
  51.                                           bool fragment,
  52.                                           bool omitEncoding
  53.                                           ) {
  54.   if (generator==NULL){
  55.      switch (type){
  56.       case TEX:
  57.         generator = new TexGenerator (styleInfoPath);
  58.         break;
  59.       case LATEX:
  60.         generator = new LatexGenerator(styleInfoPath, replaceQuotes);
  61.         break;
  62.       case RTF:
  63.         generator = new RtfGenerator (styleInfoPath);
  64.         break;
  65.       case XSLFO:
  66.           generator = new XslFoGenerator(styleInfoPath, encoding, omitEncoding,
  67.                                          fopCompatible);
  68.         break;
  69.       case XML:
  70.           generator = new XmlGenerator(styleInfoPath,encoding, omitEncoding);
  71.         break;
  72.       case XHTML:
  73.           generator = new XHtmlGenerator(styleInfoPath, encoding, omitEncoding,
  74.                                          attachAnchors);
  75.           break;
  76.       #ifndef __WXMSW__
  77.       case ANSI:
  78.         generator = new AnsiGenerator (styleInfoPath);
  79.         break;
  80.       #endif
  81.       default:
  82.           generator = new HtmlGenerator(styleInfoPath, encoding, omitEncoding,
  83.                                         attachAnchors);
  84.      }
  85.   }
  86.   generator->setType(type);
  87.   generator->setStyleInputPath(styleInPath);
  88.   generator->setStyleOutputPath(styleOutPath);
  89.   generator->setIncludeStyle(includeStyle);
  90.   generator->setPrintLineNumbers(ln);
  91.   generator->setPrintZeroes(lnz);
  92.   generator->setFragmentCode(fragment);
  93.   generator->setPreformatting(lineWrappingMode,
  94.                              (generator->getPrintLineNumbers()) ?
  95.                               MAX_LINE__WIDTH - LINE_NUMBER_WIDTH : MAX_LINE__WIDTH,
  96.                               numSpaces );
  97.   return generator;
  98. }
  99.  
  100. void CodeGenerator::deleteInstance(){
  101.   delete generator;
  102.   generator=NULL;
  103. }
  104.  
  105.  
  106. CodeGenerator::CodeGenerator():
  107.     in(NULL),
  108.     out(NULL),
  109.     maskWs(false),
  110.     excludeWs(false),
  111.     fragmentOutput(false),
  112.     showLineNumbers (false),
  113.     lineNumberFillZeroes(false),
  114.     lineNumber(0),
  115.     includeStyleDef(false),
  116.     lineIndex(0),
  117.     formatter(NULL),
  118.     preFormatter(NULL),
  119.     formattingEnabled(false),
  120.     formattingPossible(false),
  121.     outputType(highlight::HTML)
  122. {}
  123.  
  124. CodeGenerator::CodeGenerator(const string &colourTheme)
  125.    :in(NULL),
  126.     out(NULL),
  127.     maskWs(false),
  128.     excludeWs(false),
  129.     fragmentOutput(false),
  130.     showLineNumbers (false),
  131.     lineNumberFillZeroes(false),
  132.     lineNumber(0),
  133.     includeStyleDef(false),
  134.     stylePath(colourTheme),
  135.     lineIndex(0),
  136.     formatter(NULL),
  137.     preFormatter(NULL),
  138.     formattingEnabled(false),
  139.     formattingPossible(false),
  140.     outputType(highlight::HTML)
  141. {
  142.   line.reserve(100);
  143.   docStyle.load(stylePath);
  144. }
  145.  
  146. CodeGenerator::~CodeGenerator()
  147. {
  148.   delete preFormatter;
  149.   delete formatter;
  150. }
  151.  
  152.  
  153. /** Getter and Setter*/
  154.  
  155. void CodeGenerator::setPrintLineNumbers(bool flag){
  156.   showLineNumbers=flag;
  157. }
  158.  
  159. bool CodeGenerator::getPrintLineNumbers(){
  160.   return showLineNumbers;
  161. }
  162.  
  163. void CodeGenerator::setPrintZeroes(bool flag){
  164.   lineNumberFillZeroes=flag;
  165. }
  166.  
  167. bool CodeGenerator::getPrintZeroes(){
  168.   return lineNumberFillZeroes;
  169. }
  170.  
  171. void CodeGenerator::setFragmentCode(bool flag){
  172.   fragmentOutput=flag;
  173. }
  174.  
  175. void CodeGenerator::setIncludeStyle(bool flag){
  176.     includeStyleDef = flag;
  177. }
  178.  
  179. void CodeGenerator::setStyleInputPath(const string& path){
  180.     styleInputPath = path;
  181. }
  182. void CodeGenerator::setStyleOutputPath(const string& path){
  183.     styleOutputPath = path;
  184. }
  185.  
  186. const string&  CodeGenerator::getStyleInputPath(){
  187.     return styleInputPath;
  188. }
  189. const string&  CodeGenerator::getStyleOutputPath(){
  190.     return styleOutputPath;
  191. }
  192.  
  193.  
  194. bool CodeGenerator::getFragmentCode(){
  195.   return fragmentOutput;
  196. }
  197.  
  198. void CodeGenerator::setStyleName(const string& s){
  199.   stylePath=s;
  200. }
  201.  
  202. void CodeGenerator::setType(OutputType t){
  203.     outputType = t;
  204. }
  205.  
  206. const string& CodeGenerator::getStyleName(){
  207.   return stylePath;
  208. }
  209.  
  210. bool CodeGenerator::formattingDisabled(){
  211.   return !formattingEnabled;
  212. }
  213.  
  214. bool CodeGenerator::formattingIsPossible(){
  215.   return formattingPossible;
  216. }
  217.  
  218. void CodeGenerator::setPreformatting(WrapMode lineWrappingStyle,
  219.                                      unsigned int lineLength,
  220.                                      int numberSpaces ){
  221.   bool enableWrap = lineWrappingStyle!=WRAP_DISABLED;
  222.   bool replaceTabs = numberSpaces > 0;
  223.   if (enableWrap || replaceTabs)  {
  224.     preFormatter=new PreFormatter(enableWrap, replaceTabs);
  225.     if (enableWrap)
  226.       preFormatter->setWrappingProperties(lineLength, lineWrappingStyle==WRAP_DEFAULT);
  227.     if (replaceTabs)
  228.       preFormatter->setNumberSpaces(numberSpaces);
  229.   }
  230. }
  231.  
  232. /*
  233. WrapMode CodeGenerator::getLineWrapping(){
  234.   if (preFormatter==NULL) return WRAP_DISABLED;
  235.   return (preFormatter->indentCode()?WRAP_DEFAULT:WRAP_SIMPLE);
  236. }
  237. */
  238. LanguageDefinition &CodeGenerator::getLanguage(){
  239.   return langInfo;
  240. }
  241.  
  242. void CodeGenerator::reset()
  243. {
  244.   lineIndex = lineNumber = 0;
  245.   line.clear();
  246. }
  247.  
  248.  
  249. /** sucht vorwaerts ab Position searchPos Ziffer in s und liefert Integerwert
  250. der gefundenen Zahl zurueck.
  251. Im SymbolString stehen die den einzelnen Symbolen zugeordneten Konstanten
  252. immer HINTER diesen Symbolen*/
  253. State CodeGenerator::getState(const string &s, unsigned int searchPos)
  254. {
  255.   unsigned int i= searchPos+1, result=0;
  256.  
  257.   // nach Ziffer in s suchen
  258.   do {
  259.       ++i;
  260.   } while ((i<s.length()) && !isdigit(s[i])) ;
  261.  
  262.   // Zahl zusammensetzen
  263.   while ((i<s.length()) && isdigit(s[i])){
  264.     result = result *10 + (s[i]-'0');
  265.     ++i;
  266.   }
  267.   return ((result)? (State)result:_UNKNOWN);
  268. }
  269.  
  270. string CodeGenerator::getIdentifier()
  271. {
  272.   --lineIndex;
  273.   unsigned int startPos=lineIndex;
  274.   char c= line[lineIndex];
  275.  
  276.   while (    ( lineIndex < line.length()
  277.           && (   StringTools::isAlpha(c)
  278.               || isdigit(c))
  279.               || isAllowedChar(c))
  280.           )
  281.     {
  282.       ++lineIndex;
  283.       c= line[lineIndex];
  284.     }
  285.   return string(line, startPos, lineIndex - startPos);
  286. }
  287.  
  288. string CodeGenerator::getNumber()
  289. {
  290.   --lineIndex;
  291.   unsigned int startPos=lineIndex;
  292.   char c=line[lineIndex];
  293.  
  294.   while ( lineIndex < line.length() && (
  295.           isdigit(c)
  296.           // don't highlight methods applied on numbers as part of the number
  297.           // i.e. Ruby: 3.xxx()
  298.           || (c == '.' && isdigit(line[lineIndex+1]))
  299.           // '-' is accepted as first character
  300.           || (c == '-' && lineIndex == startPos)
  301.           || (StringTools::isAlpha(c) && line[lineIndex-1]=='0')
  302.           || (isxdigit(c) || c=='L' || c=='U' || c=='l' || c=='u') ))
  303.     {
  304.       ++lineIndex;
  305.       c= line[lineIndex];
  306.     }
  307.   return string(line,startPos, lineIndex-startPos);
  308. }
  309.  
  310. unsigned int CodeGenerator::getLineNumber()
  311. {
  312.   return lineNumber;
  313. }
  314.  
  315. bool CodeGenerator::readNewLine(string &newLine){
  316.   bool eof;
  317.   terminatingChar=newLine[lineIndex-1];
  318.   if (formattingPossible && formattingEnabled)
  319.    {
  320.      eof=!formatter->hasMoreLines();
  321.       if (!eof)
  322.        {
  323.          newLine = formatter->nextLine();
  324.        }
  325.    }
  326.    else  // reformatting not enabled
  327.     {
  328.       eof = ! getline( *in, newLine);
  329.     }
  330.    return eof;
  331. }
  332.  
  333. unsigned char CodeGenerator::getInputChar()
  334. {
  335.   bool eol = lineIndex == line.length();
  336.  
  337.   if (eol) {
  338.     bool eof=false;
  339.     if (preFormatter!=NULL){
  340.        if (!preFormatter->hasMoreLines()) {
  341.           eof=readNewLine(line);
  342.           preFormatter->setLine(line);
  343.        }
  344.        line = preFormatter->getNextLine();
  345.     } else {
  346.       eof=readNewLine(line);
  347.     }
  348.     lineIndex=0;
  349.     ++lineNumber;
  350.     line=StringTools::trimRight(line);
  351.     return (eof)?'\0':'\n';
  352.   }
  353.   return line[lineIndex++];
  354. }
  355.  
  356. State CodeGenerator::getCurrentState (bool lastStateWasNumber)
  357. {
  358.   unsigned char c;
  359.  
  360.   if (token.length()==0) {
  361.     c=getInputChar();
  362.   }  else {
  363.     lineIndex-= (token.length()-1);
  364.     c=token[0];
  365.   }
  366.   if (c=='\n'){
  367.     return _EOL;   // End of line
  368.   }
  369.  
  370.   if (c=='\0') {
  371.     return _EOF;   // End of file
  372.   }
  373.  
  374.   if (isspace(c)) {
  375.       token= c;
  376.       return _WS;
  377.     }
  378.  
  379.   // numbers have to be searched before using the symbolstring,
  380.   // as numbers are part of this string
  381.   if (isdigit(c)
  382.       // recognize floats like .5
  383.       || (c=='.' && isdigit(line[lineIndex]))
  384.       // test if '-' belongs to a term like "1-2"
  385.       || ((c == '-')
  386.           && (!lastStateWasNumber)
  387.           && isdigit(StringTools::getNextNonWs(line, lineIndex))) )
  388.     {
  389.       token = getNumber();
  390.       return NUMBER;
  391.     }
  392.   unsigned int symbolLength;
  393.   size_t symbolPos;
  394.   bool found=false;
  395.   string symbols=langInfo.getSymbolString();
  396.  
  397.   symbolPos = symbols.find(c);
  398.   // search symbols (comment delimiters, directives etc.)
  399.   // before keywords, because alphabetic chars may be part of symbols, too
  400.   while ((symbolPos!= string::npos) && (!found))
  401.     {
  402.       symbolLength=symbols.find(' ', symbolPos)-symbolPos;
  403.       token = symbols.substr(symbolPos, symbolLength);
  404.  
  405.       // TODO Ruby =ende, =end bugfix (whitespace after symbol needs to be checked)
  406.  
  407.       // Abfrage nach Leerzeichen in SymbolString verhindert falsches
  408.       // Erkennen von Symbolteilen:
  409.       if (lineIndex && token == line.substr(lineIndex-1, symbolLength)
  410.                     && isspace(symbols[symbolPos-1]) ) {
  411.          found = true;
  412.          lineIndex += (symbolLength-1);
  413.       } else {
  414.         symbolPos = symbols.find_first_not_of(' ',symbols.find(' ',symbolPos));
  415.       }
  416.     }
  417.  
  418.   // dirty workaround stuff in here
  419.   if (found) {
  420.     State foundState = getState(symbols, symbolPos);
  421.  
  422.     // get the current keyword class id to apply the corresponding formatting style
  423.     if (foundState==KEYWORD_BEGIN || foundState==TAG_BEGIN ) {
  424.       currentKeywordClass=langInfo.getDelimPrefixClassID(token);
  425.     }
  426.  
  427.     // Full line quotes must start in coloumn 1 (Fortran 77)
  428.     if (langInfo.isFullLineComment() && foundState==SL_COMMENT){
  429.       if (lineIndex==1) {
  430.         return SL_COMMENT;
  431.       }
  432.     }
  433.     // VHDL Workaround: distinguish string delimiters and event markers
  434.     // (same eymbol: ')
  435.     else if (langInfo.isVHDL()
  436.              && foundState==STRING && currentState!=STRING
  437.              && lineIndex > 1
  438.              &&(isdigit(line[lineIndex-2]) || isalpha(line[lineIndex-2]))){
  439.         c=line[lineIndex-1];
  440.         // do not return, continue search...
  441.     }  else {
  442.         return foundState;
  443.     }
  444.   }
  445.  
  446.   // Alphanumerisches Token parsen und als Keyword oder Type erkennen
  447.   if (StringTools::isAlpha(c) || langInfo.isPrefix(c) || isAllowedChar(c))
  448.     {
  449.       if (langInfo.isPrefix(c)){
  450.         token = c;
  451.         ++lineIndex;
  452.         token += getIdentifier();
  453.       } else {
  454.         token = getIdentifier();
  455.       }
  456.       string reservedWord=(langInfo.isIgnoreCase()) ?
  457.                           StringTools::lowerCase(token):token;
  458.       currentKeywordClass=langInfo.isKeyword(reservedWord);
  459.       return (currentKeywordClass) ? KEYWORD : STANDARD;
  460.     }
  461.  
  462.   // Character not referring to any state
  463.   token = c;
  464.   return STANDARD;
  465. }
  466.  
  467. string CodeGenerator::maskString(const string & s)
  468. {
  469.   ostringstream ss;
  470.   for (unsigned int i=0;i< s.length();i++){
  471.       ss << maskCharacter(s[i]);
  472.   }
  473.   return ss.str();
  474. }
  475.  
  476. void CodeGenerator::printMaskedToken(bool flushWhiteSpace)
  477. {
  478.   if(flushWhiteSpace) flushWs();
  479.   *out << maskString(token);
  480.   token.clear();
  481. }
  482.  
  483. bool CodeGenerator::isAllowedChar(char c)
  484. {
  485.   return ( langInfo.getAllowedChars().find(c)!= string::npos);
  486. }
  487.  
  488. bool CodeGenerator::styleFound(){
  489.   return docStyle.found();
  490. }
  491.  
  492. bool CodeGenerator::printIndexFile(const vector<string> &fileList,
  493.                                    const string &outPath){
  494.   return true;
  495. }
  496.  
  497. bool CodeGenerator::initIndentationScheme(const string &schemePath){
  498.  
  499.   if (formatter!=NULL){
  500.     return true;
  501.   }
  502.  
  503.   ConfigurationReader indentScheme(schemePath);
  504.   if (indentScheme.found()){
  505.     if (formatter==NULL) {
  506.        formatter=new astyle::ASFormatter();
  507.  
  508.        string brackets=indentScheme.getParameter("brackets");
  509.        if (!brackets.empty()){
  510.          // Break brackets from pre-block code (i.e. ANSI C/C++ style).
  511.          if (brackets=="break"){
  512.            formatter->setBracketFormatMode(astyle::BREAK_MODE);
  513.          }
  514.          //Attach brackets to pre-block code (i.e. Java/K&R style).
  515.          else if (brackets=="attach"){
  516.            formatter->setBracketFormatMode(astyle::ATTACH_MODE);
  517.          }
  518.          // Break definition-block brackets and attach command-block brackets.
  519.          else if (brackets=="linux"){
  520.            formatter->setBracketFormatMode(astyle::BDAC_MODE);
  521.          }
  522.          // Break brackets before closing headers (e.g. 'else', 'catch', ..).
  523.          // Should be appended to --brackets=attach or --brackets=linux.
  524.          else if (brackets=="break-closing-headers"){
  525.            formatter->setBreakClosingHeaderBracketsMode(true);
  526.          }
  527.        }
  528.  
  529.        string pad=indentScheme.getParameter("pad");
  530.        if (!pad.empty()){
  531.          //Insert space paddings around parenthesies only.
  532.          if (pad=="paren"){
  533.            formatter->setParenthesisPaddingMode(true);
  534.          }
  535.          // Insert space paddings around operators only.
  536.          else if (pad=="oper"){
  537.            formatter->setOperatorPaddingMode(true);
  538.          }
  539.          //Insert space paddings around operators AND parenthesies.
  540.          else if (pad=="all"){
  541.            formatter->setOperatorPaddingMode(true);
  542.            formatter->setParenthesisPaddingMode(true);
  543.          }
  544.        }
  545.  
  546.        string oneLine=indentScheme.getParameter("one-line");
  547.        if (!oneLine.empty()){
  548.          // Don't break one-line blocks.
  549.          if (oneLine=="keep-blocks"){
  550.            formatter->setBreakOneLineBlocksMode(false);
  551.          }
  552.          // Don't break complex statements and multiple statements residing in a
  553.          // single line.
  554.          else if (oneLine=="keep-statements"){
  555.            formatter->setSingleStatementsMode(false);
  556.          }
  557.        }
  558.  
  559.        // Insert empty lines around unrelated blocks, labels, classes, ...
  560.        string breakBlocks=indentScheme.getParameter("break-blocks");
  561.        if (!breakBlocks.empty()){
  562.          if (breakBlocks=="all"){
  563.            //Like --break-blocks, except also insert empty lines around closing
  564.            //headers (e.g. 'else', 'catch', ...).
  565.            formatter->setBreakClosingHeaderBlocksMode(true);
  566.          }
  567.          formatter->setBreakBlocksMode(true);
  568.        }
  569.        string trueVal="true";
  570.  
  571.        // Other options...
  572.  
  573.        //Indent using # spaces per indent. Not specifying # will result in a
  574.        //default of 4 spaces per indent.
  575.        string indentSpaces=indentScheme.getParameter("indent-spaces");
  576.  
  577.        // Indent a minimal # spaces in a continuous conditional belonging to a
  578.        //conditional header.
  579.        string minConditionalIndent=indentScheme.getParameter("min-conditional-indent");
  580.  
  581.        // Indent a maximal # spaces in a continuous statement, relatively to the
  582.        // previous line.
  583.        string maxInStatementIndent=indentScheme.getParameter("max-instatement-indent");
  584.  
  585.        // Add extra indentation to '{' and '}' block brackets.
  586.        string indentBrackets=indentScheme.getParameter("indent-brackets");
  587.  
  588.        // Add extra indentation entire blocks (including brackets).
  589.        string indentBlocks=indentScheme.getParameter("indent-blocks");
  590.  
  591.        // Indent the contents of namespace blocks.
  592.        string indentNamespaces=indentScheme.getParameter("indent-namespaces");
  593.  
  594.        // Indent 'class' blocks, so that the inner 'public:','protected:' and
  595.        // 'private: headers are indented inrelation to the class block.
  596.        string indentClasses=indentScheme.getParameter("indent-classes");
  597.  
  598.        // Indent 'switch' blocks, so that the inner 'case XXX:' headers are
  599.        // indented in relation to the switch block.
  600.        string indentSwitches=indentScheme.getParameter("indent-switches");
  601.  
  602.        // Indent 'case XXX:' lines, so that they are flush with their bodies..
  603.        string indentCases=indentScheme.getParameter("indent-cases");
  604.  
  605.        // Indent labels so that they appear one indent less than the current
  606.        // indentation level, rather than being    flushed completely to the left
  607.        // (which is the default).
  608.        string indentLabels=indentScheme.getParameter("indent-labels");
  609.  
  610.        // Indent multi-line #define statements
  611.        string indentPreprocessor=indentScheme.getParameter("indent-preprocessor");
  612.  
  613.        // Break 'else if()' statements into two different lines.
  614.        string breakElseIfs = indentScheme.getParameter("break-elseifs");
  615.  
  616.        string javaStyle = indentScheme.getParameter("java-style");
  617.  
  618.        // default values in ASBeautifier are false, it is ok to set them false
  619.        // if parameter does not exist in scheme file
  620.        formatter->setBracketIndent(indentBrackets==trueVal);
  621.        formatter->setBlockIndent(indentBlocks==trueVal);
  622.        formatter->setNamespaceIndent(indentNamespaces==trueVal);
  623.        formatter->setClassIndent(indentClasses==trueVal);
  624.        formatter->setSwitchIndent(indentSwitches==trueVal);
  625.        formatter->setCaseIndent(indentCases==trueVal);
  626.        formatter->setLabelIndent(indentLabels==trueVal);
  627.        formatter->setPreprocessorIndent(indentPreprocessor==trueVal);
  628.        formatter->setBreakElseIfsMode(breakElseIfs==trueVal);
  629.  
  630.        if (javaStyle==trueVal){
  631.          formatter->setJavaStyle();
  632.        }
  633.  
  634.        if (!indentSpaces.empty()){
  635.          formatter->setSpaceIndentation(StringTools::str2int(indentSpaces));
  636.        }
  637.        if (!minConditionalIndent.empty()){
  638.          formatter->setMinConditionalIndentLength(
  639.                       StringTools::str2int(minConditionalIndent));
  640.        }
  641.        if (!maxInStatementIndent.empty()){
  642.          formatter->setMinConditionalIndentLength(
  643.                       StringTools::str2int(maxInStatementIndent));
  644.        }
  645.     }
  646.     formattingEnabled=(formatter != NULL);
  647.     return true;
  648.   } else {
  649.     return false;
  650.   }
  651. }
  652.  
  653. LoadResult CodeGenerator::initLanguage(const string& langDefPath){
  654.   bool reloadNecessary= langInfo.needsReload(langDefPath);
  655.   if (reloadNecessary){
  656.     bool failure = !langInfo.load(langDefPath);
  657.  
  658.     if (failure) {
  659.       return LOAD_FAILED;
  660.     }
  661.  
  662.     formattingPossible=langInfo.enableReformatting();
  663.  
  664.     if (styleTagOpen.size()>NUMBER_BUILTIN_STYLES){
  665.        // remove dynamic keyword tag delimiters of the old language definition
  666.        vector<string>::iterator keyStyleOpenBegin =
  667.            styleTagOpen.begin() + NUMBER_BUILTIN_STYLES;
  668.        vector<string>::iterator keyStyleCloseBegin =
  669.            styleTagClose.begin()+ NUMBER_BUILTIN_STYLES;
  670.        styleTagOpen.erase(keyStyleOpenBegin, styleTagOpen.end());
  671.        styleTagClose.erase(keyStyleCloseBegin, styleTagClose.end());
  672.     }
  673.     // add new keyword delimiters
  674.     for (unsigned int i=0;i< langInfo.getKeywordClasses().size(); i++){
  675.       styleTagOpen.push_back(getMatchingOpenTag(i));
  676.       styleTagClose.push_back(getMatchingCloseTag(i));
  677.     }
  678.   }
  679.   return (reloadNecessary) ? LOAD_NEW : LOAD_NONE;
  680. }
  681.  
  682. ParseError CodeGenerator::printOutput (const string & inFileName,
  683.                                        const string &outFileName)
  684. {
  685.   if (!docStyle.found()) {
  686.     return BAD_STYLE;
  687.   }
  688.   reset();
  689.  
  690.   ParseError error=PARSE_OK;
  691.  
  692.   in = (inFileName.empty()? &cin :new ifstream (inFileName.c_str()));
  693.   if (!in->fail()) {
  694.     out = (outFileName.empty()? &cout :new ofstream (outFileName.c_str()));
  695.     if ( out->fail()) {
  696.       error=BAD_OUTPUT;
  697.     }
  698.   }
  699.  
  700.   if ( in->fail()){
  701.      error=BAD_INPUT;
  702.   }
  703.  
  704.   if (error==PARSE_OK) {
  705.     if (formatter != NULL){
  706.        formatter->init(new astyle::ASStreamIterator(in));
  707.     }
  708.     if (! fragmentOutput){
  709.       *out << getHeader(inFileName);
  710.     }
  711.     printBody();
  712.     if (! fragmentOutput){
  713.       *out << getFooter();
  714.     }
  715.   }
  716.  
  717.   if (!outFileName.empty()){
  718.     delete out; out=NULL;
  719.   }
  720.   if (!inFileName.empty()) {
  721.     delete in; in=NULL;
  722.   }
  723.   return error;
  724. }
  725.  
  726.  
  727. unsigned int CodeGenerator::getStyleID(State s, unsigned int kwClassID){
  728.     if (s==KEYWORD && kwClassID){
  729.       return NUMBER_BUILTIN_STYLES + kwClassID-1;
  730.   }
  731.   return (unsigned int) s ;
  732. }
  733.  
  734. void CodeGenerator::closeTag(State s){
  735.   *out << styleTagClose[(unsigned int)s];
  736.   flushWs();
  737.   currentState=_UNKNOWN;
  738. }
  739.  
  740. void CodeGenerator::openTag(State s){
  741.   *out << styleTagOpen[(unsigned int)s];
  742.   currentState=s;
  743. }
  744.  
  745. void CodeGenerator::closeKWTag(unsigned int kwClassID){
  746.     *out << styleTagClose[getStyleID(KEYWORD, kwClassID)];
  747.  
  748.     flushWs();
  749.     currentState=_UNKNOWN;
  750. }
  751.  
  752. void CodeGenerator::openKWTag(unsigned int kwClassID){
  753.     *out << styleTagOpen[getStyleID(KEYWORD, kwClassID)];
  754.     currentState=KEYWORD;
  755. }
  756.  
  757.  
  758. ///////////////////////////////////////////////////////////////////////////////
  759.  
  760. void CodeGenerator::processRootState()
  761. {
  762.   if (langInfo.highlightingDisabled()){
  763.      string line;
  764.      while (getline(*in, line)){
  765.        *out << maskString(line) << getNewLine();
  766.      }
  767.      *out << flush;
  768.      return;
  769.   }
  770.  
  771.   State state=STANDARD;
  772.  
  773.   bool eof=false,
  774.        firstLine=true; // avoid newline before printing the first output line
  775.   openTag(STANDARD);
  776.   do {
  777.     // determine next state
  778.     state= getCurrentState(state==NUMBER);
  779.     // handle current state
  780.     switch(state)
  781.       {
  782.       case KEYWORD:
  783.       case KEYWORD_BEGIN:
  784.         closeTag(STANDARD);
  785.         eof=processKeywordState(state);
  786.         openTag(STANDARD);
  787.         break;
  788.       case NUMBER:
  789.         closeTag(STANDARD);
  790.         eof=processNumberState();
  791.         openTag(STANDARD);
  792.         break;
  793.       case ML_COMMENT_BEGIN:
  794.         closeTag(STANDARD);
  795.         eof=processMultiLineCommentState();
  796.         openTag(STANDARD);
  797.         break;
  798.       case SL_COMMENT:
  799.         closeTag(STANDARD);
  800.         eof=processSingleLineCommentState();
  801.         openTag(STANDARD);
  802.         break;
  803.       case STRING:
  804.         closeTag(STANDARD);
  805.         eof=processStringState(STANDARD);
  806.         openTag(STANDARD);
  807.         break;
  808.       case DIRECTIVE_LINE:
  809.         closeTag(STANDARD);
  810.         eof=processDirectiveState();
  811.         openTag(STANDARD);
  812.         break;
  813.       case TAG_BEGIN:
  814.         closeTag(STANDARD);
  815.         eof=processTagState();
  816.         openTag(STANDARD);
  817.         break;
  818.       case ESC_CHAR:
  819.         if (langInfo.allowExtEscSeq()){
  820.           closeTag(STANDARD);
  821.           eof=processEscapeCharState();
  822.           openTag(STANDARD);
  823.         } else {
  824.           printMaskedToken();
  825.         }
  826.         break;
  827.       case SYMBOL:
  828.         closeTag(STANDARD);
  829.         eof=processSymbolState();
  830.         openTag(STANDARD);
  831.         break;
  832.       case _EOL:
  833.         insertLineNumber(!firstLine);
  834.         firstLine=false;
  835.         break;
  836.       case _EOF:
  837.         eof=true;
  838.         break;
  839.       case _WS:
  840.         processWsState();
  841.         break;
  842.       default:
  843.         printMaskedToken();
  844.         break;
  845.       }
  846.     }
  847.   while (!eof);
  848.   closeTag(STANDARD);
  849.   *out << getNewLine();
  850.   *out << flush;
  851. }
  852.  
  853. bool CodeGenerator::processKeywordState(State myState){
  854.   State newState=STANDARD;
  855.   unsigned int myClassID=currentKeywordClass;
  856.   bool eof=false,
  857.        exitState=false;
  858.  
  859.    openKWTag(myClassID);
  860.   do {
  861.     printMaskedToken(newState!=_WS);
  862.     newState= getCurrentState();
  863.     switch(newState)
  864.       {
  865.       case _WS:
  866.         processWsState();
  867.         break;
  868.       case _EOL:
  869.         insertLineNumber();
  870.         exitState=true;
  871.         break;
  872.       case _EOF:
  873.         eof = true;
  874.         break;
  875.       case KEYWORD_END:
  876.          if (myState==KEYWORD_BEGIN){
  877.            printMaskedToken();
  878.          }
  879.          exitState=true;
  880.         break;
  881.       default:
  882.         exitState=    myState!=KEYWORD_BEGIN
  883.                    &&((myClassID!=currentKeywordClass)||(myState!=newState));
  884.         break;
  885.       }
  886.   } while ((!exitState) && (!eof));
  887.  
  888.   closeKWTag(myClassID);
  889.  
  890.   currentKeywordClass=0;
  891.   return eof;
  892. }
  893.  
  894. bool CodeGenerator::processNumberState(){
  895.   State newState=STANDARD;
  896.   bool eof=false,
  897.        exitState=false;
  898.  
  899.   openTag(NUMBER);
  900.   do {
  901.     printMaskedToken(newState!=_WS);
  902.     newState= getCurrentState(true);
  903.     switch(newState)
  904.       {
  905.       case _WS:
  906.         processWsState();
  907.         break;
  908.       case _EOL:
  909.         insertLineNumber();
  910.         exitState=true;
  911.         break;
  912.       case _EOF:
  913.         eof = true;
  914.         break;
  915.       default:
  916.         exitState=newState!=NUMBER;
  917.         break;
  918.       }
  919.   } while ((!exitState) && (!eof));
  920.  
  921.   closeTag(NUMBER);
  922.   return eof;
  923. }
  924.  
  925. bool CodeGenerator::processMultiLineCommentState()
  926. {
  927.   int commentCount=1;
  928.   State newState=STANDARD;
  929.   bool eof=false, exitState=false;
  930.  
  931.   openTag(ML_COMMENT_BEGIN);
  932.   do {
  933.     printMaskedToken(newState!=_WS);
  934.     newState= getCurrentState();
  935.  
  936.     switch(newState)
  937.       {
  938.       case _WS:
  939.         processWsState();
  940.         break;
  941.       case _EOL:
  942.         wsBuffer += styleTagClose[ML_COMMENT_BEGIN];
  943.         insertLineNumber();
  944.         wsBuffer += styleTagOpen[ML_COMMENT_BEGIN];
  945.         break;
  946.       case _EOF:
  947.         eof = true;
  948.         break;
  949.       case ML_COMMENT_BEGIN:
  950.         if (langInfo.allowNestedMLComments()) {
  951.               ++commentCount;
  952.         }
  953.         break;
  954.       case ML_COMMENT_END:
  955.         commentCount--;
  956.         if (!commentCount){
  957.             printMaskedToken();
  958.             exitState=true;
  959.         }
  960.         break;
  961.       default:
  962.         break;
  963.       }
  964.   } while ((!exitState) && (!eof));
  965.  
  966.   closeTag(ML_COMMENT_BEGIN);
  967.   return eof;
  968. }
  969.  
  970. bool CodeGenerator::processSingleLineCommentState()
  971. {
  972.  
  973.   //if ( checkSpecialCmd()) return false;
  974.  
  975.   State newState=STANDARD;
  976.   bool eof=false, exitState=false;
  977.  
  978.   openTag(SL_COMMENT);
  979.   do {
  980.     printMaskedToken(newState!=_WS);
  981.     newState= getCurrentState();
  982.  
  983.     switch(newState)
  984.       {
  985.       case _WS:
  986.         processWsState();
  987.         break;
  988.      case _EOL:
  989.         printMaskedToken();
  990.         insertLineNumber();
  991.         exitState=true;
  992.         break;
  993.       case _EOF:
  994.         eof = true;
  995.         break;
  996.       default:
  997.         break;
  998.       }
  999.   } while ((!exitState) && (!eof));
  1000.  
  1001.   closeTag(SL_COMMENT);
  1002.   return eof;
  1003. }
  1004.  
  1005. bool CodeGenerator::processDirectiveState()
  1006. {
  1007.   State  newState=STANDARD;
  1008.   bool eof=false, exitState=false;
  1009.  
  1010.   openTag(DIRECTIVE_LINE);
  1011.   do {
  1012.     printMaskedToken(newState!=_WS);
  1013.     newState= getCurrentState();
  1014.     switch(newState)
  1015.       {
  1016.       case _WS:
  1017.         processWsState();
  1018.         break;
  1019.       case DIRECTIVE_LINE_END:
  1020.         printMaskedToken();
  1021.         exitState=true;
  1022.         break;
  1023.       case _EOL:
  1024.         printMaskedToken();
  1025.         exitState=(terminatingChar!=langInfo.getContinuationChar());
  1026.         if (!exitState) wsBuffer += styleTagClose[DIRECTIVE_LINE];
  1027.         insertLineNumber();
  1028.         if (!exitState) wsBuffer += styleTagOpen[DIRECTIVE_LINE];
  1029.         break;
  1030.       case ML_COMMENT_BEGIN:
  1031.         closeTag(DIRECTIVE_LINE);
  1032.         eof= processMultiLineCommentState();
  1033.         openTag(DIRECTIVE_LINE);
  1034.         break;
  1035.       case SL_COMMENT:
  1036.         closeTag(DIRECTIVE_LINE);
  1037.         eof= processSingleLineCommentState();
  1038.         openTag(DIRECTIVE_LINE);
  1039.         exitState=true;
  1040.         break;
  1041.       case STRING:
  1042.         closeTag(DIRECTIVE_LINE);
  1043.         eof=processStringState(DIRECTIVE_LINE);
  1044.         openTag(DIRECTIVE_LINE);
  1045.         break;
  1046.       case _EOF:
  1047.         eof = true;
  1048.         break;
  1049.       default:
  1050.         break;
  1051.       }
  1052.   } while ((!exitState) && (!eof));
  1053.  
  1054.   closeTag(DIRECTIVE_LINE);
  1055.   return eof;
  1056. }
  1057.  
  1058. bool CodeGenerator::processStringState(State oldState)
  1059. {
  1060.   State newState=STANDARD;
  1061.   bool eof=false, exitState=false;
  1062.   bool returnedFromOtherState=false;
  1063.   // Test if character before string open delimiter token equals to the
  1064.   // raw string prefix (Example: r" ", r""" """ in Python)
  1065.   bool isRawString=
  1066.          line[lineIndex-token.length()-1]==langInfo.getRawStringPrefix();
  1067.  
  1068.   string openStringDelimiter=token;
  1069.  
  1070.   State myState= (oldState==DIRECTIVE_LINE) ? DIRECTIVE_STRING : STRING;
  1071.   openTag(myState);
  1072.   do {
  1073.     // true if last token was an escape char
  1074.     if (!returnedFromOtherState) {
  1075.          printMaskedToken(newState!=_WS);
  1076.     }
  1077.     returnedFromOtherState=false;
  1078.     newState= getCurrentState();
  1079.  
  1080.     switch(newState)
  1081.       {
  1082.       case _WS:
  1083.         processWsState();
  1084.         break;
  1085.       case _EOL:
  1086.         wsBuffer += styleTagClose[myState];
  1087.         insertLineNumber();
  1088.         wsBuffer += styleTagOpen[myState];
  1089.         //exitState=true;
  1090.         break;
  1091.       case ML_COMMENT_END:
  1092.         printMaskedToken();
  1093.         break;
  1094.       case STRING:
  1095.         exitState= openStringDelimiter==token;
  1096.         printMaskedToken();
  1097.         break;
  1098.       case ESC_CHAR:
  1099.         if (!isRawString){
  1100.            closeTag(myState);
  1101.            eof=processEscapeCharState();
  1102.            openTag(myState);
  1103.            returnedFromOtherState=true;
  1104.         }
  1105.         break;
  1106.       case _EOF:
  1107.         eof = true;
  1108.         break;
  1109.       default:
  1110.         printMaskedToken();
  1111.         break;
  1112.       }
  1113.   } while ((!exitState) && (!eof));
  1114.  
  1115.   closeTag(myState);
  1116.   return eof;
  1117. }
  1118.  
  1119. bool CodeGenerator::processTagState()
  1120. {
  1121.   State  newState=STANDARD;
  1122.   bool eof=false, exitState=false, returnedFromOtherState=false;
  1123.   unsigned int myKeywordClass=currentKeywordClass;
  1124.  
  1125.   openTag(KEYWORD);
  1126.   do {
  1127.     if (!returnedFromOtherState) {
  1128.        printMaskedToken(newState!=_WS);
  1129.     }
  1130.     returnedFromOtherState = false;
  1131.     newState= getCurrentState();
  1132.  
  1133.     switch(newState)
  1134.       {
  1135.       case _WS:
  1136.         processWsState();
  1137.         break;
  1138.       case _EOL:
  1139.         insertLineNumber();
  1140.         exitState=true;
  1141.         break;
  1142.       case TAG_END:
  1143.         printMaskedToken();
  1144.         exitState=true;
  1145.         break;
  1146.       case STRING:
  1147.         closeTag(KEYWORD);
  1148.         eof=processStringState(KEYWORD);
  1149.         currentKeywordClass=myKeywordClass;
  1150.         openTag(KEYWORD);
  1151.         returnedFromOtherState = true;
  1152.         break;
  1153.       case ESC_CHAR:
  1154.         closeTag(KEYWORD);
  1155.         eof=processEscapeCharState();
  1156.         currentKeywordClass=myKeywordClass;
  1157.         openTag(KEYWORD);
  1158.         returnedFromOtherState = true;
  1159.         break;
  1160.       case NUMBER:
  1161.         closeTag(KEYWORD);
  1162.         eof=processNumberState();
  1163.         currentKeywordClass=myKeywordClass;
  1164.         openTag(KEYWORD);
  1165.         returnedFromOtherState = true;
  1166.         break;
  1167.       case _EOF:
  1168.         eof = true;
  1169.         break;
  1170.       default:
  1171.         printMaskedToken();
  1172.         break;
  1173.       }
  1174.   } while ((!exitState) && (!eof));
  1175.  
  1176.   closeTag(KEYWORD);
  1177.   currentKeywordClass=0;
  1178.  
  1179.   return eof;
  1180. }
  1181.  
  1182. bool CodeGenerator::processSymbolState(){
  1183.  
  1184.   State newState=STANDARD;
  1185.   bool eof=false,
  1186.        exitState=false;
  1187.  
  1188.   openTag(SYMBOL);
  1189.   do {
  1190.     printMaskedToken(newState!=_WS);
  1191.     newState= getCurrentState(true);
  1192.     switch(newState)
  1193.       {
  1194.      case _WS:
  1195.         processWsState();
  1196.         break;
  1197.       case _EOL:
  1198.         insertLineNumber();
  1199.         exitState=true;
  1200.         break;
  1201.       case _EOF:
  1202.         eof = true;
  1203.         break;
  1204.       default:
  1205.         exitState=newState!=SYMBOL;
  1206.         break;
  1207.       }
  1208.   } while ((!exitState) && (!eof));
  1209.  
  1210.   closeTag(SYMBOL);
  1211.   return eof;
  1212. }
  1213.  
  1214. bool CodeGenerator::processEscapeCharState()
  1215. {
  1216.   State newState=STANDARD;
  1217.   bool eof=false, exitState=false;
  1218.  
  1219.   openTag(ESC_CHAR);
  1220.   do {
  1221.     printMaskedToken(newState!=_WS);
  1222.     skipEscapeSequence();
  1223.     newState= getCurrentState();
  1224.     switch(newState)
  1225.       {
  1226.       case _EOL:
  1227.         insertLineNumber();
  1228.         exitState=true;
  1229.         break;
  1230.       case _WS:
  1231.         processWsState();
  1232.         --lineIndex;
  1233.         break;
  1234.       case _EOF:
  1235.         eof = true;
  1236.         break;
  1237.       default:
  1238.         exitState=newState!=ESC_CHAR;
  1239.         break;
  1240.       }
  1241.   } while ((!exitState) && (!eof));
  1242.  
  1243.   closeTag(ESC_CHAR);
  1244.   return eof;
  1245. }
  1246.  
  1247. void  CodeGenerator::skipEscapeSequence(){
  1248.   if (lineIndex<line.length()){
  1249.     char c=line[lineIndex];
  1250.     int charsToSkip=1;
  1251.     // Escape Sequenz /ooo Oktal, /x000 hex, /u00xx Java unicode
  1252.     if (isdigit(c) ){
  1253.       // \0 abfangen
  1254.       while ( isdigit(line[lineIndex+charsToSkip]) && charsToSkip<4) {
  1255.         ++charsToSkip;
  1256.       }
  1257.     } else if (tolower(c)=='x'){
  1258.       charsToSkip=langInfo.isJava() ? 4 : 3;
  1259.     } else if (tolower(c)=='u'){
  1260.       charsToSkip=5;
  1261.     }
  1262.     while (charsToSkip-- && lineIndex++<line.length()){
  1263.        *out <<maskCharacter(line[lineIndex-1]);
  1264.     }
  1265.   }
  1266. }
  1267.  
  1268.  
  1269. void CodeGenerator::processWsState()
  1270. {
  1271.   if (!maskWs) {
  1272.     wsBuffer += token;
  1273.     token.clear();
  1274.     return;
  1275.   }
  1276.   flushWs();
  1277.   int cntWs=0;
  1278.   lineIndex--;
  1279.  
  1280.    while (isspace(line[lineIndex])  ) {
  1281.     ++cntWs;
  1282.     ++lineIndex;
  1283.   }
  1284.  
  1285.   if (cntWs>1) {
  1286.     unsigned int styleID=getStyleID(currentState, currentKeywordClass);
  1287.     if (excludeWs && styleID!=_UNKNOWN) {
  1288.         *out << styleTagClose[styleID];
  1289.     }
  1290.     *out << maskWsBegin;
  1291.     for (int i=0; i<cntWs; i++){
  1292.         *out << spacer;
  1293.     }
  1294.     *out << maskWsEnd;
  1295.     if (excludeWs && styleID!=_UNKNOWN){
  1296.         *out << styleTagOpen[styleID];
  1297.     }
  1298.   } else {
  1299.     *out << token;
  1300.   }
  1301.   token.clear();
  1302. }
  1303.  
  1304. void CodeGenerator::flushWs(){
  1305.    *out<<wsBuffer;
  1306.    wsBuffer.clear();
  1307. }
  1308.  
  1309. bool CodeGenerator::isFirstNonWsChar() {
  1310.   unsigned int i=lineIndex-1;
  1311.   while (i--){
  1312.     if (!isspace(line[i])){
  1313.       return false;
  1314.     }
  1315.   }
  1316.   return true;
  1317. }
  1318.  
  1319. string CodeGenerator::getNewLine(){
  1320.   return newLineTag;
  1321. }
  1322.  
  1323. void CodeGenerator::insertLineNumber(bool insertNewLine) {
  1324.     if (insertNewLine){
  1325.     wsBuffer += getNewLine();
  1326.   }
  1327.   if (showLineNumbers) {
  1328.     ostringstream os;
  1329.     ostringstream numberPrefix;
  1330.     if (lineNumberFillZeroes) {
  1331.       os.fill('0');
  1332.     }
  1333.     os <<setw(LINE_NUMBER_WIDTH) << right << lineNumber;
  1334.  
  1335.     numberPrefix << styleTagOpen[LINENUMBER]
  1336.          << maskString(os.str()) << spacer
  1337.          << styleTagClose[LINENUMBER];
  1338.  
  1339.     wsBuffer += numberPrefix.str();
  1340.   }
  1341. }
  1342.  
  1343. unsigned int CodeGenerator::getLineIndex(){
  1344.   return lineIndex;
  1345. }
  1346.  
  1347. bool CodeGenerator::printExternalStyle(const string &outFile)
  1348. {
  1349.     if (!includeStyleDef && langInfo.getSyntaxHighlight()) {
  1350.         ofstream cssOutFile(outFile.c_str());
  1351.         if (cssOutFile) {
  1352.             cssOutFile << styleCommentOpen
  1353.                     <<" Style definition file generated by highlight "
  1354.                     << HIGHLIGHT_VERSION << ", " << HIGHLIGHT_URL
  1355.                     << " " << styleCommentClose << "\n";
  1356.             cssOutFile << "\n"<<styleCommentOpen<<" Highlighting theme definition: "
  1357.                     << styleCommentClose << "\n\n"
  1358.                     << getStyleDefinition()
  1359.                     << "\n";
  1360.             cssOutFile << readUserStyleDef();
  1361.             cssOutFile.close();
  1362.         } else {
  1363.             return false;
  1364.         }
  1365.     }
  1366.     return true;
  1367. }
  1368.  
  1369. string CodeGenerator::readUserStyleDef(){
  1370.     ostringstream ostr;
  1371.     if (!styleInputPath.empty()){
  1372.         ifstream userStyleDef(styleInputPath.c_str());
  1373.         if (userStyleDef) {
  1374.             ostr << "\n"<<styleCommentOpen<<" Content of "<<styleInputPath<<": "<<styleCommentClose<<"\n";
  1375.             string line;
  1376.             while (getline(userStyleDef, line)){
  1377.                 ostr << line << "\n";
  1378.             }
  1379.             userStyleDef.close();
  1380.         } else {
  1381.             ostr << styleCommentOpen<<" ERROR: Could not include "
  1382.                     << styleInputPath
  1383.                     << "."<<styleCommentClose<<"\n";
  1384.         }
  1385.     }
  1386.     return ostr.str();
  1387. }
  1388.  
  1389. bool CodeGenerator::checkSpecialCmd(){
  1390.     bool insertNL = (lineIndex-token.length());
  1391.     cerr << "token: "<<token<< " index"<< lineIndex << " "<<line [ lineIndex ]<<endl;
  1392.  
  1393.     if (line [ lineIndex ]=='!'){
  1394.       // find cmd
  1395.       size_t cmdPos1 = line.find('@', lineIndex+1);
  1396.  
  1397.       cerr << "cmdPos"<<cmdPos1<<endl;
  1398.       if(cmdPos1==string::npos) return false;
  1399.       size_t cmdPos2=cmdPos1+1;
  1400.       while (cmdPos2 < line.length() && StringTools::isAlpha(line[cmdPos2])) cmdPos2++;
  1401.       cerr << "cmdPos2"<<cmdPos2<<endl;
  1402.       cerr << line.substr(cmdPos1, cmdPos2)<<endl;
  1403.  
  1404.       // hide comment line
  1405.       token.clear();
  1406.       lineIndex=line.length();
  1407.       getInputChar(); lineNumber--;
  1408.       if (insertNL) { lineNumber++;insertLineNumber();};
  1409.       // end hide
  1410.  
  1411.       return true;
  1412.     }
  1413.  
  1414.     return false;
  1415. }
  1416.  
  1417. }
  1418.